<template>
    <div>
        <el-form-item :label="formLabel" prop="area" :rules="rules.area">
            <el-cascader
                v-model="form.area"
                ref="cascaderRef"
                placeholder="请选择省市区"
                :options="state.addressList"
                :props="cascaderProps"
                @change="e => onAreaChange(e, 'click')"
                @visible-change="handleVisibleChange" />
        </el-form-item>
        <el-form-item label=" " prop="street" class="street" :rules="rules.street">
            <div class="align_center">
                <el-input v-model.trim="form.street" placeholder="请输入详细地址" clearable />
                <el-button @click="querySearch"> 搜索地图 </el-button>
            </div>
        </el-form-item>
        <el-form-item label="地图定位" prop="lng" class="map_ten" :rules="rules.lng">
            <div class="map_container">
                <div id="container"></div>
                <div class="keyword_list">
                    <el-scrollbar v-if="state.isSearch" :infinite-scroll-distance="50" v-infinite-scroll="onLoadData">
                        <div class="header">搜索结果(共{{ state.total }})条</div>
                        <div>
                            <div
                                class="item"
                                v-for="(item, index) in state.keywordList"
                                :style="{ backgroundColor: index === state.activeIndex ? '#f5f5f5' : '' }"
                                :key="item.id"
                                @click="onSelectMap(index)">
                                <div class="left">{{ index + 1 }}.</div>
                                <div class="right">
                                    <div class="title">{{ item.title }}</div>
                                    <div class="address">{{ item.address }}</div>
                                    <div class="phone">{{ item.phone || '' }}</div>
                                </div>
                            </div>
                        </div>
                    </el-scrollbar>
                </div>
            </div>
        </el-form-item>
    </div>
</template>

<script setup>
import request from '@/request';
import { reactive, ref, watch, nextTick, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';

const props = defineProps({
    type: { type: String, default: 'shop' },
    data: { type: Object, default: () => ({}) }
});
const emit = defineEmits(['change']);
const formLabel = props.type == 'shop' ? '店铺地址' : '自提点地址';
const form = reactive({
    area: [],
    street: '',
    lng: ''
});
const rules = reactive({
    area: [{ required: true, message: `请选择${formLabel}`, trigger: ['blur', 'change'] }],
    street: [{ required: true, message: '请输入详细地址', trigger: 'blur' }],
    lng: [{ required: true, message: '请确认地理位置', trigger: ['blur', 'change'] }]
});

watch(
    () => props.data,
    v => {
        Object.assign(form, v);
    },
    { immediate: true, deep: true }
);
watch(
    () => form,
    v => {
        emit('change', v);
    },
    { deep: true }
);

/* ************************************获取地区列表-选择省市区-start************************************ */
const cascaderProps = {
    emitPath: true,
    label: 'name',
    value: 'id'
};
const cascaderRef = ref(null);
const getAddressList = async () => {
    const { data } = await request('regionServ', { level: 3 });
    if (Array.isArray(data)) {
        data.splice(0, 1);
        state.addressList.push(...data);
    }
};
getAddressList();

const handleVisibleChange = async visible => {
    if (visible && state.addressList.length === 0) {
        getAddressList();
    }
};
const onAreaChange = (v, type) => {
    if (!v) return;
    form.provinceId = v[0] || '';
    form.cityId = v[1] || '';
    form.areaId = v[2] || '';
    form.townId = v[3] || '';
    state.region = cascaderRef.value.getCheckedNodes()[0].pathLabels[1] || '';
    if (type === 'click') {
        form.street = '';
    }
};
/* ************************************获取地区列表-选择省市区-end************************************ */

/* ************************************地图定位-start************************************ */
// 获取区id
const getAreaId = async code => {
    let target;
    JSON.stringify(state.addressList, (key, value) => {
        if (code == value.code) {
            target = value;
            return;
        }
        return value;
    });
    if (!target?.id) return;
    form.area = target.id;
    nextTick(() => {
        form.area = cascaderRef.value?.getCheckedNodes()[0].pathValues;
        onAreaChange(form.area);
    });
};

const state = reactive({
    addressList: [], // 地址列表
    region: '', // 限定搜索的城市名称
    isSearch: false,
    activeIndex: -1, // 选中的搜索结果
    keywordList: [], // 搜索结果列表
    total: 0 // 搜索结果总数
});
const TMap = window.TMap;
let map, // 地图实例
    infoWindow, // 信息窗口
    marker, // 标记
    markerArr, // 标记数组
    bounds, // 地图边界
    Suggestion, // 搜索服务
    Geocoder; // 地址解析服务

// 初始化标记
const initMarker = geometries => {
    if (marker) {
        marker.setMap(null);
        marker.destroy();
    }

    marker = null;
    marker = new TMap.MultiMarker({
        id: 'marker-layer',
        map: map,
        zIndex: 100000000, //层级
        styles: {
            default: new TMap.MarkerStyle({
                //点标注的相关样式
                width: 19, //宽度
                height: 31, //高度
                zIndex: 100000000, //层级
                src: '', //标注点图片url或base64地址
                color: '#fff', //标注点文本颜色
                size: 10, //标注点文本文字大小
                offset: { x: 0, y: -5 } //标注点文本文字基于direction方位的偏移属性
            }),
            active: new TMap.MarkerStyle({
                //点标注的相关样式
                width: 19, //宽度
                height: 31, //高度
                src: '', //标注点图片url或base64地址
                color: '#fff', //标注点文本颜色
                size: 10, //标注点文本文字大小
                offset: { x: 0, y: -5 } //标注点文本文字基于direction方位的偏移属性
            })
        },
        geometries: geometries
    });
    // marker.on('click', markerClick);
};

// 初始化信息窗
const initInfoWindow = (latLng, data) => {
    //初始化infoWindow
    if (!infoWindow) {
        infoWindow = new TMap.InfoWindow({
            map: map,
            position: new TMap.LatLng(39.984104, 116.307503),
            offset: { x: 0, y: -35 } //设置信息窗相对position偏移像素
        });
    }
    infoWindow.open(); //打开信息窗
    infoWindow.setPosition(latLng); //设置信息窗位置
    infoWindow.setContent(` <div class="map_info_window">
           ${data.title ? `<div class="map_info_window_title">${data.title}</div>` : ''}
            <div class="map_info_window_content">${data.address}</div>
        </div>`); //设置信息窗内容
};

// 地图点击
const mapClick = async ({ latLng }) => {
    state.isSearch = false;
    state.keywordList = [];
    form.lat = latLng.lat;
    form.lng = latLng.lng;
    markerArr = [];
    //设置infoWindow
    initMarker([
        {
            id: 'demo',
            styleId: 'default',
            position: latLng,
            properties: {
                title: 'marker'
            }
        }
    ]);
    try {
        const res = await Geocoder.getAddress({ location: latLng });
        if (res.status === 0) {
            if (!form.street) form.street = res.result?.address_component?.street_number;
            initInfoWindow(latLng, { address: res.result?.address });
            form.address = res.result?.address;
            getAreaId(res.result?.ad_info?.adcode);
        } else {
            ElMessage.error(res.message);
        }
    } catch (error) {
        initInfoWindow(latLng, { address: '' });
    }
};

// 搜索结果选中
const onSelectMap = index => {
    state.activeIndex = index;
    markerArr.forEach(item => {
        item.styleId = 'default';
    });
    markerArr[index].styleId = 'active';
    initMarker(markerArr);
    map.setCenter(markerArr[index].position);
    const currentItem = state.keywordList[index];
    if (!form.street) form.street = currentItem.address;
    form.lat = currentItem.location.lat;
    form.lng = currentItem.location.lng;
    form.address = currentItem.address;
    initInfoWindow(markerArr[index].position, { title: currentItem.title, address: currentItem.address });
    map?.setZoom(18);
    getAreaId(currentItem.adcode);
};

//设置自适应显示marker
const showMarker = () => {
    bounds = null;
    bounds = new TMap.LatLngBounds();
    if (markerArr.length) {
        //判断标注点是否在范围内
        markerArr.forEach(item => {
            //若坐标点不在范围内，扩大bounds范围
            if (bounds.isEmpty() || !bounds.contains(item.position)) {
                bounds.extend(item.position);
            }
        });
        //设置地图可视范围
        map?.fitBounds(bounds, {
            padding: 100 // 自适应边距
        });
    }
};

// 初始化地图
const initMap = center => {
    //初始化地图
    map = new TMap.Map('container', {
        rotation: 360, //设置地图旋转角度
        pitch: 0, //设置俯仰角度（0~45）
        zoom: 12, //设置地图缩放级别
        center: center //设置地图中心点坐标
    });

    //监听marker点击事件
    // marker.on('click', eventClick);
    //初始化
    //监听地图点击事件
    map.on('click', mapClick);
    // 关键字搜索服务库
    Suggestion = new TMap.service.Suggestion({
        pageSize: 20,
        regionFix: false // 固定在当前城市
    });
    // 地址解析服务库
    Geocoder = new TMap.service.Geocoder();
};
// 滚动到底部加载更多
const onLoadData = async () => {
    if (state.keywordList.length >= state.total) return;
    const res = await Suggestion.getSuggestions({
        keyword: form.street,
        pageIndex: state.keywordList.length / 20 + 1
    });
    state.keywordList = [...state.keywordList, ...res.data];
    markerArr = state.keywordList.map((item, index) => {
        return {
            id: item.id,
            styleId: 'default',
            position: item.location,
            content: `${index + 1}`,
            properties: {
                title: item.title
            }
        };
    });
    initMarker(markerArr);
    state.total = res.count || 0;
};
// 关键字搜索
const querySearch = async () => {
    state.isSearch = false;
    if (infoWindow) infoWindow.close();
    if (!form.street) {
        state.keywordList.length = 0;
        state.total = 0;
        return;
    }
    Suggestion.setRegion(state.region);
    Suggestion.setRegionFix(!!form.area?.length);
    const res = await Suggestion.getSuggestions({
        keyword: form.street
    });

    state.keywordList = Array.isArray(res.data) ? res.data : [];
    state.total = res.count || 0;
    markerArr = state.keywordList.map((item, index) => {
        return {
            id: item.id,
            styleId: 'default',
            position: item.location,
            content: `${index + 1}`,
            properties: {
                title: item.title
            }
        };
    });
    initMarker(markerArr);
    showMarker();
    await nextTick();
    state.isSearch = true;
};

/* ************************************地图定位-end************************************ */

// 回显地图
const onShowMap = async data => {
    let center = new TMap.LatLng(31.22114, 121.54409);
    if (data) {
        center = new TMap.LatLng(+data.lat, +data.lng);
        initMap(center);
        initMarker([
            {
                id: data.id,
                styleId: 'default',
                position: center,
                properties: {
                    title: data.title
                }
            }
        ]);
        initInfoWindow(center, { address: data.address || '' });
        await nextTick();
        state.region = cascaderRef.value.getCheckedNodes()[0]?.pathLabels[1] || '';
    } else {
        initMap(center);
    }
};

// 离开页面时销毁地图&标记&弹窗
onUnmounted(() => {
    map?.destroy();
    marker?.destroy();
    infoWindow?.destroy();
});
defineExpose({
    onShowMap
});
</script>

<style lang="scss" scoped>
:deep(.el-cascader) {
    width: 420px;
}
:deep(.el-input) {
    width: 420px;
    margin-right: 8px;
}
.align_center {
    display: flex;
    align-items: center;
}
.street {
    :deep(.el-form-item__label) {
        font-size: 0;
    }
}
.map_ten {
    :deep(.el-form-item__content) {
        display: block;
    }
}
.map_container {
    position: relative;
    width: 100%;
    border: 1px solid #dcdfe6;

    .keyword_list {
        position: absolute;
        top: 0;
        left: 0;
        width: 300px;
        max-height: 400px;
        overflow-y: auto;
        z-index: 1000;
        background: #fff;
        overflow: auto;
        .header {
            padding-left: 5px;
            color: #909399;
        }
        .item {
            display: flex;
            padding: 5px 10px;
            &:hover {
                cursor: pointer;
                background: #f5f7fa;
            }
            .left {
                line-height: 18px;
            }
            .right {
                .title {
                    font-size: 14px;
                    line-height: 18px;
                    color: #6ab1f9;
                    font-weight: bold;
                    margin-bottom: 10px;
                }
                .address {
                    font-size: 12px;
                    line-height: 16px;
                    color: #909399;
                }
            }
        }
    }
}
#container {
    // width: 700px;
    height: 400px;
}
</style>
<style lang="scss">
.map_info_window {
    line-height: 1;
    margin: -23px -10px -12px;
    padding: 10px 30px 10px 10px;
    background-color: #fff;
    border-radius: 10px;
    text-align: left;
    .map_info_window_title {
        font-size: 14px;
        font-weight: bold;
        margin-bottom: 10px;
    }
    .map_info_window_content {
        font-size: 12px;
        line-height: 24px;
        color: #606266;
    }
}
</style>
